﻿using Castle.DynamicProxy;
using Core.AutoFacService.Abstract;
using Core.AutoFacService.Attributes.InjectAttributes;
using Core.AutoFacService.Attributes.InterceptorAttributes;
using SqlSugarAndEntity.Base;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Core.AutoFacService.Interceptor.Transaction
{
	[Component]
	public class TransactionInterceptor : AbstractInterceptor
	{
		private static AsyncLocal<bool> asyncLocal = new AsyncLocal<bool>();
		private readonly IBaseMethod baseMethod;
		public TransactionInterceptor(IBaseMethod baseMethod,IEnumerable<Assembly> dlls) : base(dlls)
		{
			this.baseMethod = baseMethod;
			asyncLocal.Value = false;
		}

		public override IEnumerable<Type> GetInterceptorTypes()
		{
			return dlls.SelectMany(t => t.GetTypes())
				.Where(a => !string.IsNullOrEmpty(a.Namespace) && (a.Namespace.StartsWith("Services")|| a.Namespace.StartsWith("Repository")));
		}

		public override void Intercept(IInvocation invocation)
		{
			Console.WriteLine("事务执行了");
			this.ToInterceptor().Intercept(invocation);
		}

		public override void InterceptAsynchronous(IInvocation invocation)
		{
			invocation.ReturnValue = InternalInterceptAsynchronous(invocation);
		}

		public override void InterceptAsynchronous<TResult>(IInvocation invocation)
		{
			Console.WriteLine("事务执行了");
			invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation);
		}

		public override void InterceptSynchronous(IInvocation invocation)
		{
			if (HasTransaction(invocation))
			{
				baseMethod.Db().BeginTran();
				try
				{
					asyncLocal.Value = true;
					invocation.Proceed();
					baseMethod.Db().CommitTran();
				}
				catch
				{
					baseMethod.Db().RollbackTran();
					throw;
				}
				finally
				{
					asyncLocal.Value = false;
				}
			}
			else
			{
				invocation.Proceed();
			}
		}

		private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation)
		{
			if (HasTransaction(invocation))
			{
				baseMethod.Db().BeginTran();
				try
				{
					asyncLocal.Value = true;
					invocation.Proceed();
					Task<TResult> task = (Task<TResult>)invocation.ReturnValue;
					TResult result = await task;//获得返回结果
					baseMethod.Db().CommitTran();
					return result;
				}
				catch
				{
					baseMethod.Db().RollbackTran();
					throw;
				}
				finally
				{
					asyncLocal.Value = false;
				}
			}
			else
			{
				//调用业务方法
				invocation.Proceed();
				Task<TResult> task = (Task<TResult>)invocation.ReturnValue;
				TResult result = await task;//获得返回结果
				return result;
			}

		}

		private async Task InternalInterceptAsynchronous(IInvocation invocation)
		{
			if (HasTransaction(invocation))
			{
				baseMethod.Db().BeginTran();
				try
				{
					asyncLocal.Value = true;
					invocation.Proceed();
					Task task = (Task)invocation.ReturnValue;
					baseMethod.Db().CommitTran();
					await task;//获得返回结果
				}
				catch
				{
					baseMethod.Db().RollbackTran();
					throw;
				}
				finally
				{
					asyncLocal.Value = false;
				}
			}
			else
			{
				//调用业务方法
				invocation.Proceed();
				Task task = (Task)invocation.ReturnValue;
				await task;//获得返回结果
			}
		}

		private bool HasTransaction(IInvocation invocation)
		{
			var method = invocation.MethodInvocationTarget;
			return method.GetCustomAttributes(true).Where(t => t.GetType() == typeof(TransactionAttribute)).FirstOrDefault() != null && !asyncLocal.Value;
		}
	}
}
